import csv, os, time

from .thread import CmdThread, StreamThread


class BccCollect(object):
    """
    BccCollect read from infile, Each line is a particular probe in bcc_dir/tools/
    """

    def __init__(self, bccPath, probes, timeout, output, interval):
        self.interval = interval
        self.timeout = timeout
        self.bccPath = bccPath
        self.probes = probes
        self.output = output
        self.log2Type = ["runqlat", "biolatency"]
        self.log2Collect, self.streamCollect = [], []
        self.threads = []

    def collect(self):
        self.prepare_output_file()
        getPath = lambda probe: self.bccPath + "/tools/" + probe
        # stream bcc (cachestat)
        for probe in self.streamCollect:
            probePath = getPath(probe)
            # we don't track streamrthreads...
            thread = StreamThread(probePath, "/".join([self.output, probe]))
            thread.start()

        # log2 bcc (runqlat, biolatency)
        while True:
            for probe in self.log2Collect:
                probePath = getPath(probe)
                self.run_cmd(probePath, probe)
            time.sleep(self.interval + self.timeout)

            # actually, it is not necessaily to join......
            for thread in self.threads:
                thread.join()
            self.threads = []

    def run_cmd(self, probePath, probe):
        outputFile = "/".join([self.output, probe])
        cmds = [
            "timeout -s SIGINT",
            str(self.timeout) + "s",
            probePath,
        ]
        cmd = " ".join(cmds)
        thread = CmdThread(cmd, "log2", outputFile)
        self.threads.append(thread)
        thread.start()

    def prepare_output_file(self):
        """write column names to each output file"""
        for probe in self.probes:
            if not os.path.isfile(self.bccPath + "/tools/" + probe):
                print(probePath, "not exist")  # TODO use logging
                self.probes.remove(probe)
                continue

            outputFile = "/".join([self.output, probe])
            columns = ["timestamp"]
            if probe in self.log2Type:
                self.log2Collect.append(probe)
                columns.extend([str(i) for i in range(64)])
                with open(outputFile, "w") as csvfile:
                    csvWriter = csv.writer(csvfile, delimiter=",")
                    csvWriter.writerow(columns)
            else:
                self.streamCollect.append(probe)


class PerfStatCollect(object):
    """
    PerfStatCollect executes `perf stat -e event1,event2,...,eventx`
    """

    def __init__(self, timeout, interval, output, events, pids=[]):
        self.interval = interval
        self.timeout = timeout
        self.events = events
        self.outputFile = "/".join([output, "perfstat.csv"])
        self.pids = pids

    def collect(self):
        self.prepare_output_file()
        while True:
            self.run_cmd()
            time.sleep(self.interval + self.timeout)

    def run_cmd(self):
        cmd = [
            "timeout -s SIGINT",
            str(self.timeout),
            "perf stat -e",
            ",".join(self.events),
            "-x , 2>&1",
        ]
        if self.pids:
            cmd.extend(["-p", ",".join(pids)])
        cmd = " ".join(cmd)
        thread = CmdThread(cmd, "perfstat", self.outputFile)
        thread.start()

    def prepare_output_file(self):
        """write column names to output file"""
        columns = ["timestamp"]
        columns.extend(self.events)
        with open(self.outputFile, "w") as csvfile:
            csvWriter = csv.writer(csvfile, delimiter=",")
            csvWriter.writerow(columns)
